﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;

namespace Cemit.PolyServer
{
    /// <summary>
    /// 基于Console实现的更多功能的控制台
    /// </summary>
    public static class Debug
    {
        /// <summary>
        /// 读入一行数据，如果满足condition，则返回
        /// </summary>
        public static string Read(Func<string, bool> condition, string hint = null, string errorHint = null)
        {
            return Read(condition, s => s, hint, errorHint);
        }

        /// <summary>
        /// 读入一行数据，如果满足condition，则使用converter转换后返回
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="condition">条件</param>
        /// <param name="converter">转换器</param>
        /// <param name="hint">每次输入前的提示（不自动添加回车或空格）</param>
        /// <param name="errorHint">输出错误后的提示（自动添加回车）</param>
        /// <returns></returns>
        public static T Read<T>(Func<string, bool> condition, Func<string, T> converter, string hint = null, string errorHint = null)
        {
            T ret = default;
            bool isCondition = false;
            do
            {
                if (!string.IsNullOrEmpty(hint))
                {
                    Console.Write(hint);
                }

                string input = Console.ReadLine();
                if (condition(input))
                {
                    ret = converter(input);
                    isCondition = true;
                }
                else if(!string.IsNullOrEmpty(errorHint))
                {
                    Console.WriteLine(errorHint);
                }

            } while (!isCondition);
            return ret;
        }

        /// <summary>
        /// 一直读取，直到读取到一行整数
        /// </summary>
        public static int ReadInt()
        {
            int ret = -1;
            while (!int.TryParse(Console.ReadLine(), out ret)) { }
            return ret;
        }

        /// <summary>输出一个详细等级的日志</summary>
        public static void Log(this object obj, object message, [CallerLineNumber] int sourceLine = 0)
        {
            Console.WriteLine($"[{GetTime()}] {obj.GetType().Name} (line:{sourceLine}): {message}");
        }

        /// <summary>输出一个信息等级的日志</summary>
        public static void LogInfo(this object obj, object message, [CallerLineNumber] int sourceLine = 0)
        {
            Console.WriteLine($"[{GetTime()}] {obj.GetType().Name} (line:{sourceLine}): {message}");
        }

        /// <summary>输出一个警告等级的日志</summary>
        public static void LogWarning(this object obj, object message, [CallerLineNumber] int sourceLine = 0)
        {
            Console.WriteLine($"[{GetTime()}] !warning! {obj.GetType().Name} (line:{sourceLine}): {message}");
        }

        /// <summary>输出一个错误等级的日志</summary>
        public static void LogError(this object obj, object message, [CallerLineNumber] int sourceLine = 0)
        {
            Console.WriteLine($"[{GetTime()}] !!!error!!! {obj.GetType().Name} (line:{sourceLine}): {message}");
        }

        /// <summary>输出一个详细等级的日志</summary>
        public static void Log(object message, [CallerLineNumber] int sourceLine = 0)
        {
            Console.WriteLine($"[{GetTime()}] {GetClassName()} (line:{sourceLine}): {message}");
        }

        /// <summary>输出一个信息等级的日志</summary>
        public static void LogInfo(object message, [CallerLineNumber] int sourceLine = 0)
        {
            Console.WriteLine($"[{GetTime()}] {GetClassName()} (line:{sourceLine}): {message}");
        }

        /// <summary>输出一个警告等级的日志</summary>
        public static void LogWarning(object message, [CallerLineNumber] int sourceLine = 0)
        {
            Console.WriteLine($"[{GetTime()}] !warning! {GetClassName()} (line:{sourceLine}): {message}");
        }

        /// <summary>输出一个错误等级的日志</summary>
        public static void LogError(object message, [CallerLineNumber] int sourceLine = 0)
        {
            System.Console.WriteLine($"[{GetTime()}] !!!error!!! {GetClassName()} (line:{sourceLine}): {message}");
        }

        private static string GetTime()
        {
            return DateTime.Now.ToLongTimeString();
        }

        private static string GetClassName()
        {
            return new StackTrace()
                .GetFrame(2)
                .GetMethod()
                .ReflectedType
                .Name;
        }
    }
}
